/**
 * tigerrad
 * fall 2006
 */

#ifndef _ENGINE_H
#define _ENGINE_H

#include "Util.h"
#include "Scene.h"
#include "Program.h"
#include "Framebuffer.h"
#include "Camera.h"
#include "Light.h"
#include "FloatTexture.h"

/**
 * 3D renderer using OpenGL.
 */
class Engine
{
	public:
		/**
		 * Constructor.
		 */
		Engine();

		/**
		 * Init OpenGL and engine state.
		 * @param size Init window size.
		 */
		void init(const Vec2s& size);

		/**
		 * Handle window resize.
		 * @param size Window size 
		 */
		void resize(const Vec2s& size);
		
		/**
		 * Set the current Scene.
		 */
		void setScene(ScenePtr s) { _scene = s; }

		/**
		 * Render the current scene.
		 */
		void render();

		/**
		 * Set the number of secondary lights.
		 */
		void setNumSecLights(GLuint num) { _numSecLights = num; }
		
		/**
		 * Return the number of secondary lights.
		 */
		GLuint getNumSecLights() { return _numSecLights; }

		/**
		 * Set radiosity on or off.
		 */
		void setRadiosity(bool rad) { _radOn = rad; }

		/**
		 * Return true if radiosity is on.
		 */
		bool getRadiosity() { return _radOn; }

		/**
		 * Toggle radiosity on and off.
		 */
		void toggleRadiosity() { _radOn = !_radOn; }

		/**
		 * Toggle displaying the view from the light.
		 */
		void toggleShowFromLight() { _showFromLight = !_showFromLight; }

	private:
		/**
		 * Render the scene from the light into a RenderTarget.
		 * @param l AreaLight to render from
		 * @param c The main camera from which the scene will be viewed from.
		 */
		void renderFromLight(AreaLightPtr l, const Camera& c);

		/**
		 * Render deferred shader textures
		 * @param l Arealight in scene
		 * @param c Main camera
		 */
		void renderDS(AreaLightPtr l, const Camera& c);

		/**
		 * Render the final image
		 * @param rad Use radiosity
		 */
		void renderFinal(bool rad);

		/**
		 * Render deferred shader textures
		 */
		void renderDS(const Camera& c);

		/**
		 * Render secondary light textures
		 */
		void renderSecLights();

		/**
		 * Render each Entity instance in the Scene using the light 
		 * and from the camera.
		 */
		void drawEntities(AreaLightPtr l, const Camera& c);

		/**
		 * Draw the model
		 */
		void drawModel(ModelPtr m);

		/**
		 * Draw the light
		 */
		void drawLight(AreaLightPtr l);

		/**
		 * Draw a full screen quad.
		 */
		void drawFullScreenQuad();

		/**
		 * Da Scene...
		 */
		ScenePtr _scene;

		/**
		 * Deferred shader programs.
		 */
		ProgramPtr _dsProg; 

		/**
		 * Deferred shader textures.
		 */
		TexturePtr _ds[3];

		/**
		 * Framebuffers used to render to textures.
		 */
		FramebufferPtr _fboFromLight;
		FramebufferPtr _fboDS;
		FramebufferPtr _fboFinal;

		/**
		 * Shaders to render from the light
		 */
		ProgramPtr _fromLightProg; 

		/**
		 * Render textures from the light.
		 * 0 is ec
		 * 1 is normal
		 * 2 is color
		 */
		TexturePtr _fromLight[3];
		
		/**
		 * The image rendered with standard lighting
		 */
		TexturePtr _standard;

		/**
		 * The default GLSL program.
		 */
		ProgramPtr _defaultProgram;

		/**
		 * Secondary light GLSL program.
		 */
		ProgramPtr _secLightProgram;

		/**
		 * Window width,height
		 */
		Vec2s _size;	

		/**
		 * Number of secondary lights
		 */
		GLuint _numSecLights;

		/**
		 * Secondary light indexes into textures
		 */
		Vec2f* _secLightIndexes;

		/**
		 * Radiosity is on.
		 */
		bool _radOn;

		/**
		 * Show the diffuse view from the light
		 */
		bool _showFromLight;

};

typedef boost::shared_ptr<Engine> EnginePtr;

#endif

